package org.zebra.tenant;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.zebra.tenant.config.TenantProperties;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.function.Supplier;

/**
 * @author zhanghongbin
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class TenantHelper {

    private static final ThreadLocal<Serializable> DYNAMIC_TENANT_ID = new TransmittableThreadLocal<>();

    public static String HEADER_TENANT_ID = "tenant-id";

    /**
     * 是否忽略租户
     */
    static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>();

    /**
     * 租户功能是否启用
     *
     * @return true, false
     */
    public static boolean isEnabled() {
        return SpringUtil.getBean(TenantProperties.class).getEnabled();
    }

    public static String getIdType() {
        return SpringUtil.getBean(TenantProperties.class).getIdType();
    }

    /**
     * 手动设置租户忽略
     */
    public static void setIgnore(Runnable runnable) {
        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
        IGNORE.set(true);
        try {
            runnable.run();
        } finally {
            InterceptorIgnoreHelper.clearIgnoreStrategy();
            IGNORE.remove();
        }
    }

    public static void setIgnore() {
        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
        IGNORE.set(true);
    }

    public static void clearIgnore() {
        InterceptorIgnoreHelper.clearIgnoreStrategy();
        IGNORE.remove();
    }

    /**
     * 手动设置租户忽略
     */
    public static <T> T setIgnore(Supplier<T> handle) {
        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
        IGNORE.set(true);
        try {
            return handle.get();
        } finally {
            InterceptorIgnoreHelper.clearIgnoreStrategy();
            IGNORE.remove();
        }
    }

    public static boolean isIgnore() {
        return Boolean.TRUE.equals(IGNORE.get());
    }

    public static void setDynamicTenantId(Serializable tenantId) {
        DYNAMIC_TENANT_ID.set(tenantId);
    }

    public static void clearDynamicTenantId() {
        DYNAMIC_TENANT_ID.remove();
    }

    public static <T> T dynamic(Serializable tenantId, Supplier<T> handle) {
        if (isEnabled()) {
            DYNAMIC_TENANT_ID.set(tenantId);
        }
        try {
            return handle.get();
        } finally {
            DYNAMIC_TENANT_ID.remove();
        }
    }

    /**
     * 获取当前租户id
     *
     * @return 值
     */
    public static <T> T getTenantId() {
        if (!isEnabled()) {
            return null;
        }
        Serializable dynamicTenantId = DYNAMIC_TENANT_ID.get();
        if (!ObjUtil.isNull(dynamicTenantId)) {
            return (T) dynamicTenantId;
        }
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) return null;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        Object tenantId = request.getAttribute(HEADER_TENANT_ID);
        if (ObjUtil.isNull(tenantId)) {
            tenantId = SpringUtil.getBean(TenantIdAcquirer.class).getTenantId(request);
        }
        return (T) tenantId;
    }
}
